home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Frameworks / Recursive Shell 1.0.1 / Examples / ListFiles ƒ / GetFolder.c < prev    next >
Text File  |  1996-06-14  |  7KB  |  241 lines

  1. /*****************************************************************************/
  2. //
  3. //    GetFolder.c
  4. //
  5. //    This source code displays the standard file dialog box, modified to allow
  6. //    the user to select a folder instead of a file.
  7. //    Code provided by Andrew Duncan.
  8. //
  9. //    Version 1.0
  10. //
  11. //    Created:    13 May 1996
  12. //    Modified:    14 June 1996
  13. //
  14. /*****************************************************************************/
  15.  
  16. #define    CustomGetFolderDialogID    129
  17. #define    kSelectItem                13
  18.  
  19. #define    kCanSelectDesktop        false
  20.  
  21. #include "GetFolder.h"
  22.     
  23.  
  24. //
  25. //    SameFile
  26. //
  27. static Boolean SameFile(FSSpec *spec1, FSSpec *spec2)
  28.     {
  29.     return (    (spec1->vRefNum == spec2->vRefNum)
  30.             &&    (spec1->parID == spec2->parID)
  31.             &&    (EqualString( spec1->name, spec2->name, false, true)) );
  32.     }
  33.  
  34.  
  35. //
  36. //    AppendStrToStr
  37. //
  38. static void AppendStrToStr(StringPtr dst, StringPtr src, unsigned char maxDstLen)
  39.     {
  40.     short offset = dst[0]+1;
  41.     short size   = src[0];
  42.     
  43.     if ( dst[0] + src[0] > maxDstLen) size = maxDstLen - dst[0];
  44.     BlockMove( src+1, dst+offset, size);
  45.     dst[0] += size;
  46.     }
  47.  
  48. static FSSpec gDeskFolderSpec;
  49.  
  50. //
  51. //    SetSelectButtonName
  52. //
  53. // Gets the "Select" button from the CustomGetFile dialog and
  54. // the filename string from the FSSpec parameter.  It set the buttons name 
  55. // to Select “filename”, truncating the filemane if needed.  The button is
  56. // dimmed if kCanSelectDesktop==false and the FSSpec=the desktop folder.
  57. //
  58. static void SetSelectButtonName ( FSSpec *spec, DialogPtr theDlg )
  59.     {
  60.     Str255        btnName = "\p";
  61.     Str255        selectString = "\pSelect";    // Should really be a resource...
  62.     Str63        desktopFName = "\pDesktop";    // Ditto.
  63.     Str63        selNameTrunc = "\p";
  64.     Rect        iRect;
  65.     Handle        iHndl;
  66.     short        btnWidth;
  67.     short        iType;
  68.     Boolean        hilited = true;
  69.     
  70.     if (SameFile(spec, &gDeskFolderSpec))
  71.         {
  72.         AppendStrToStr(selNameTrunc, desktopFName, 63) ;
  73.         hilited = kCanSelectDesktop;
  74.         }
  75.     else
  76.         AppendStrToStr(selNameTrunc, spec->name, 63) ;
  77.     
  78.     
  79.     GetDItem(theDlg,kSelectItem,&iType,&iHndl,&iRect);
  80.     
  81.     /* truncate select name to fit in button */
  82.     btnWidth = iRect.right - iRect.left;
  83.     btnWidth -= StringWidth(selectString);
  84.     btnWidth -= StringWidth("\p “”  ");
  85.     TruncString(btnWidth, selNameTrunc, smTruncMiddle);
  86.     
  87.     /* build button name string */
  88.     AppendStrToStr(btnName, selectString, 255) ;
  89.     AppendStrToStr(btnName, "\p “", 255) ;
  90.     AppendStrToStr(btnName, selNameTrunc, 255) ;
  91.     AppendStrToStr(btnName, "\p”", 255) ;
  92.     
  93.     SetCTitle((ControlRef)iHndl, btnName);
  94.  
  95.     if (hilited)
  96.         HiliteControl((ControlRef)iHndl,0);
  97.     else
  98.         HiliteControl((ControlRef)iHndl,255);        
  99.     }
  100.  
  101.  
  102. //
  103. //    MyDlgHook
  104. //
  105. static pascal short MyDlgHook ( short item, DialogPtr theDlg, void* userData )
  106.     {
  107.     StandardFileReply*    reply;
  108.     FSSpec                curSpec;
  109.     OSType                refCon;
  110.     static FSSpec        lastSpec;                /* Remember lastSpec so that we don't update Select button needlessly    */
  111.     OSErr                err;
  112.     
  113.     refCon = GetWRefCon(theDlg);
  114.     if (refCon != sfMainDialogRefCon)
  115.         return item;
  116.     
  117.     reply = (StandardFileReply*) userData;
  118.     
  119.     if (item == sfHookFirstCall)                 /* if the dialog is just about to appear */
  120.         lastSpec.vRefNum = -9999;                /* init to ridiculous value */
  121.     
  122.     if (item == sfHookNullEvent)                /* if we got a NullEvent */
  123.         {
  124.         if ( !SameFile( &(reply->sfFile), &lastSpec) )
  125.             {
  126.             curSpec = reply->sfFile;
  127.             err = FSMakeFSSpec(curSpec.vRefNum, curSpec.parID, curSpec.name, &curSpec);
  128.             // MakeCanonFSSpec(&curSpec);
  129.             SetSelectButtonName(&curSpec, theDlg);
  130.             lastSpec = reply->sfFile ;
  131.             }
  132.         }
  133.     
  134.     if (item == kSelectItem) item = sfItemOpenButton;
  135.         
  136.     return item;
  137.     }
  138.  
  139.  
  140. //
  141. //    MyFilterAllFiles
  142. //
  143. // A file filter proc that removes everything but directories from the 
  144. // CustomGetFile list.  This means that only Folders, Volumes, or Aliases of
  145. // Folders or Volumes will appear in the list.
  146. //
  147. static pascal Boolean MyFilterAllFiles(CInfoPBPtr pb, void* /*myDataPtr*/)
  148.     {
  149.     if (pb->hFileInfo.ioFlAttrib & (1 << 4))    /* file is a directory */
  150.         return false;
  151.     return true;
  152.     }
  153.  
  154.  
  155. //
  156. //    CustomGetFolder
  157. //
  158. OSErr CustomGetFolder(StandardFileReply *reply)
  159.     {
  160.     Point            where = {-1,-1};                /* center dialog on main screen */
  161.     OSErr            err;
  162.     Boolean            targetIsFolder,wasAliased;
  163.     FileFilterYDUPP ffUPP;
  164.     DlgHookYDUPP      dhUPP;
  165.     
  166.  
  167.     err = FindFolder(kOnSystemDisk,
  168.                      kDesktopFolderType,
  169.                      kDontCreateFolder,
  170.                      &gDeskFolderSpec.vRefNum,
  171.                      &gDeskFolderSpec.parID);                        
  172.     gDeskFolderSpec.name[0] = '\0';
  173.     err = FSMakeFSSpec(gDeskFolderSpec.vRefNum, gDeskFolderSpec.parID, gDeskFolderSpec.name, &gDeskFolderSpec);
  174.  
  175.     
  176.     ffUPP = NewFileFilterYDProc(MyFilterAllFiles);
  177.     dhUPP = NewDlgHookYDProc(MyDlgHook);
  178.     
  179.  
  180.     CustomGetFile(    ffUPP,                        /* file filter proc */
  181.                     -1,                            /* number of file types */
  182.                     nil,                        /* array of file types */
  183.                     reply,                        /* the StandardFileReply structure */
  184.                     CustomGetFolderDialogID,    /* the dialog's ID */
  185.                     where,                        /* position of dialog on screen */
  186.                     dhUPP,                        /* the Dialog Hook procedure */
  187.                     nil,                        /* no modal dialog filterProc */
  188.                     nil,                        /* no activeListPtr */
  189.                     nil,                        /* no activateProc */
  190.                     reply                        /* yourDataPtr: pass reply in so that */
  191.                 );                                /* MyDlgHook() can access current info */
  192.  
  193.     if ( !reply->sfGood )                        /* if the user hit cancel button */
  194.         return noErr ;                            /* then nothing more to do so return */
  195.         
  196.     
  197.     // If we were inside a folder with no subfolders, reply->sfFile.parID will be the
  198.     // ID of the folder (not that of its parent) and the string will be null. In that
  199.     // case, don’t try to resolve the alias.
  200.     if (reply->sfFile.name[0] != '\0')
  201.         {
  202.         err = ResolveAliasFile( &(reply->sfFile), true, &targetIsFolder, &wasAliased);
  203.         if (err) return err ;
  204.         }
  205.     
  206.     
  207.     // If is not a directory or volume (e.g. we were inside a folder with no subfolders.
  208.     if ( !reply->sfIsFolder && !reply->sfIsVolume )
  209.         {
  210.         FSSpec        tempSpec;
  211.         CInfoPBRec    infoPB;
  212.         Boolean        IsDirectory;
  213.  
  214.         tempSpec = reply->sfFile;
  215.         if (tempSpec.name[0] != '\0') return; //err
  216.  
  217.         infoPB.dirInfo.ioNamePtr = tempSpec.name;
  218.         infoPB.dirInfo.ioVRefNum = tempSpec.vRefNum;
  219.         infoPB.dirInfo.ioDrDirID = tempSpec.parID;
  220.         infoPB.dirInfo.ioFDirIndex = -1;
  221.         
  222.         err = PBGetCatInfo( &infoPB, false );
  223.         if (err) return err ;
  224.         
  225.         tempSpec.parID = infoPB.dirInfo.ioDrParID ;
  226.         
  227.         // make sure that it's a directory
  228.         IsDirectory = (infoPB.dirInfo.ioFlAttrib & 0x10) ;
  229.         if ( !IsDirectory ) return; //err
  230.         
  231.         reply->sfFile = tempSpec ;
  232.         reply->sfScript = infoPB.dirInfo.ioDrFndrInfo.frScript ;
  233.         reply->sfFlags = infoPB.dirInfo.ioDrUsrWds.frFlags ;
  234.         reply->sfIsFolder = (tempSpec.parID == 1) ? (0x00) : (0xFF) ;
  235.         reply->sfIsVolume = (tempSpec.parID == 1) ? (0xFF) : (0x00) ; ;
  236.         }
  237.     
  238.     return noErr;
  239.     }
  240.  
  241.